#include "CDDraw.h"



HRESULT CDDraw::CopySurface( LPDIRECTDRAWSURFACE *ppDestSurface, LPDIRECTDRAWSURFACE *ppSrcSurface )
{
	HRESULT			hRet;
	DDSURFACEDESC	ddsSrcDesc;
	DDRAW_INIT_DDSD( ddsSrcDesc );
	hRet = (*ppSrcSurface)->GetSurfaceDesc( &ddsSrcDesc );

	DDSURFACEDESC ddsDestDesc;
	DDRAW_INIT_DDSD( ddsDestDesc );
	ddsDestDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
	ddsDestDesc.dwWidth = ddsSrcDesc.dwWidth;
	ddsDestDesc.dwHeight = ddsSrcDesc.dwHeight;

	hRet = m_pDD->CreateSurface( &ddsDestDesc, ppDestSurface,  NULL );

	hRet = (*ppDestSurface)->Blt( NULL, (*ppSrcSurface), NULL, DDBLT_WAITNOTBUSY, NULL );

	return hRet;

}



void CDDraw::CreateSrcRect( RECT &rcSrc, LPDIRECTDRAWSURFACE pSrcSurface, PPOINT pCenterPoint )
{
	DDRAW_INIT_DDSD( m_DDSDesc );
	m_pDDSBack->GetSurfaceDesc( &m_DDSDesc );

	DDSURFACEDESC ddsdSrc;
	DDRAW_INIT_DDSD( ddsdSrc );
	pSrcSurface->GetSurfaceDesc( &ddsdSrc );

	if( pCenterPoint )
	{
		rcSrc.left		= pCenterPoint->x - ( m_DDSDesc.dwWidth >> 1 );
		rcSrc.right		= pCenterPoint->x + ( m_DDSDesc.dwWidth >> 1 );
		rcSrc.top		= pCenterPoint->y - ( m_DDSDesc.dwHeight >> 1 );
		rcSrc.bottom	= pCenterPoint->y + ( m_DDSDesc.dwHeight >> 1 );

		if( rcSrc.left < 0 )
		{
			rcSrc.left	= 0;
			rcSrc.right	= m_DDSDesc.dwWidth;

		}
		else if( rcSrc.right > ddsdSrc.dwWidth )
		{
			rcSrc.left	= ddsdSrc.dwWidth - m_DDSDesc.dwWidth;
			rcSrc.right	= ddsdSrc.dwWidth;

		}

		if( rcSrc.top < 0 )
		{
			rcSrc.top		= 0;
			rcSrc.bottom	= m_DDSDesc.dwHeight;

		}
		else if( rcSrc.bottom > ddsdSrc.dwHeight )
		{
			rcSrc.top		= ddsdSrc.dwHeight - m_DDSDesc.dwHeight;
			rcSrc.bottom	= ddsdSrc.dwHeight;

		}
	}
	else
	{
		rcSrc.top		= 0;
		rcSrc.left		= 0;
		rcSrc.bottom	= m_DDSDesc.dwHeight;
		rcSrc.right		= m_DDSDesc.dwWidth;
	}

}



//
void CDDraw::DestroyCDDraw()
{
	if( m_pClipper != NULL )
	{
		m_pClipper->Release();
		m_pClipper = NULL;

	}

	if( m_pDDSBack != NULL )
	{
		m_pDDSBack->Release();
		m_pDDSBack = NULL;

	}

	if( m_pDDSPrimary != NULL )
	{
		m_pDDSPrimary->Release();
		m_pDDSPrimary = NULL;

	}

	if( m_pDD != NULL )
	{
		m_pDD->Release();
		m_pDD = NULL;

	}

}



//
HRESULT CDDraw::FlipSurfaceX( LPDIRECTDRAWSURFACE pSurface )
{
	pSurface->Lock( NULL, &m_DDSDesc, DDLOCK_WAITNOTBUSY, NULL );

	WORD	wTemp;
	DWORD	dwWidth		= m_DDSDesc.dwWidth >> 1;
	WORD	*pBuffer	= (WORD *)m_DDSDesc.lpSurface;

	for( int y = 0; y < m_DDSDesc.dwHeight; ++y )
	{
		for( int x = 0; x < dwWidth; ++x )
		{
			wTemp = pBuffer[ x + ( y * m_DDSDesc.lPitch >> 1 ) ];
			pBuffer[ x + ( y * m_DDSDesc.lPitch >> 1 ) ] = pBuffer[ m_DDSDesc.dwWidth - 1 - x + ( y * m_DDSDesc.lPitch >> 1 ) ];
			pBuffer[ m_DDSDesc.dwWidth - 1 - x + ( y * m_DDSDesc.lPitch >> 1 ) ] = wTemp;

		}

	}

	pSurface->Unlock(NULL);

	return S_OK;

}



//
HRESULT CDDraw::InitCDDraw( CMzWndEx* pWnd, bool bFullScreen )
{
	DDCAPS			ddCaps;
	DDCAPS			ddHelCaps;
	HRESULT			hRet;

	m_pWnd			= pWnd;
	m_bFullScreen	= bFullScreen;
	m_WindowRect	= MzGetWorkArea();
//	GetClientRect( m_pWnd->m_hWnd, &m_WindowRect );

	m_BackRect.top = m_WindowRect.top + BACKBUFFER_TOP;
	m_BackRect.bottom = m_WindowRect.bottom - BACKBUFFER_BOTTOM;
	m_BackRect.left = m_WindowRect.left + BACKBUFFER_LEFT;
	m_BackRect.right = m_WindowRect.right - BACKBUFFER_RIGHT;

	hRet = DirectDrawCreate( NULL, &m_pDD, NULL );
	if( FAILED( hRet ) )
		return InitFail( hRet, TEXT("DirectDrawCreate failed.") );

	m_pDD->GetCaps( &ddCaps, &ddHelCaps );

	if( m_bFullScreen && ( ddCaps.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER ) && ( ddCaps.ddsCaps.dwCaps & DDSCAPS_FLIP ) )
	{
		hRet = m_pDD->SetCooperativeLevel( m_pWnd->m_hWnd, DDSCL_FULLSCREEN );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("SetCooperativeLevel fullscreen failed.") );

		m_bSingleBuffer = false;

		DDRAW_INIT_DDSD( m_DDSDesc );
		m_DDSDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		m_DDSDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP;
		m_DDSDesc.dwBackBufferCount = 1;

		hRet = m_pDD->CreateSurface( &m_DDSDesc, &m_pDDSPrimary, NULL );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("CreateSurface Primary failed.") );

		hRet = m_pDDSPrimary->EnumAttachedSurfaces( &m_pDDSBack,EnumFunction );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("EnumAttachedSurfaces failed.") );

	}
	else
	{
		m_bSingleBuffer = true;

		hRet = m_pDD->SetCooperativeLevel( m_pWnd->m_hWnd, DDSCL_NORMAL );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("SetCooperativeLevel normal failed.") );

		DDRAW_INIT_DDSD( m_DDSDesc );
		m_DDSDesc.dwFlags = DDSD_CAPS;
		m_DDSDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

		hRet = m_pDD->CreateSurface( &m_DDSDesc, &m_pDDSPrimary, NULL );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("CreateSurface Primary failed.") );

		DDRAW_INIT_DDSD( m_DDSDesc );
		m_DDSDesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
		m_DDSDesc.dwWidth = m_BackRect.Width();
		m_DDSDesc.dwHeight = m_BackRect.Height();

        hRet = m_pDD->CreateSurface( &m_DDSDesc, &m_pDDSBack,  NULL );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("CreateSurface BackBuffer Failed.") );
	}

	//
	hRet = m_pDD->CreateClipper( 0, &m_pClipper, NULL );
	if( FAILED( hRet ) )
		return InitFail( hRet, TEXT("CreateClipper failed.") );

	hRet = m_pClipper->SetHWnd( 0, m_pWnd->m_hWnd );
	if( FAILED( hRet ) )
		return InitFail( hRet, TEXT("SetHWnd failed.") );

	hRet = m_pDDSPrimary->SetClipper( m_pClipper );
	if( FAILED( hRet ) )
		return InitFail( hRet, TEXT("SetClipper failed.") );

	//
	LPRGNDATA pRGNData;
	RECT rcClipper = { 0, 0, m_BackRect.right - m_BackRect.left, m_BackRect.bottom - m_BackRect.top };

	hRet = m_pDD->CreateClipper( 0, &m_pBackClipper, NULL );
	if( FAILED( hRet ) )
		return InitFail( hRet, TEXT("CreateClipper failed.") );

	pRGNData = ( LPRGNDATA )malloc( sizeof( RGNDATAHEADER ) + sizeof( RECT ) );

	if( pRGNData )
	{
		memcpy( pRGNData->Buffer, &rcClipper, sizeof( RECT ) );

		pRGNData->rdh.dwSize = sizeof( RGNDATAHEADER );
		pRGNData->rdh.iType = RDH_RECTANGLES;
		pRGNData->rdh.nCount = 1;
		pRGNData->rdh.nRgnSize = sizeof( RECT );
		pRGNData->rdh.rcBound = rcClipper;

		hRet = m_pBackClipper->SetClipList( pRGNData, 0 );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("SetClipList failed.") );

		hRet = m_pDDSBack->SetClipper( m_pBackClipper );
		if( FAILED( hRet ) )
			return InitFail( hRet, TEXT("SetClipper failed.") );

		free( pRGNData );

	}

	ClearBackSurface();
	BcakToPrimary();

	return S_OK;

}



//
HRESULT CDDraw::SetColorKey( LPDIRECTDRAWSURFACE pdds, COLORREF rgb )
{
	if( m_bColorKey )
	{
		DDCOLORKEY ddck;

		COLORREF rgbT;
		HDC hdc;
		DWORD dw = CLR_INVALID;
		DDSURFACEDESC ddsd;
		HRESULT hres;

		if( rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK )  
		{  
			rgbT = GetPixel( hdc, 0, 0 );
			SetPixel( hdc, 0, 0, rgb );
			pdds->ReleaseDC( hdc );

		}
		else
			return S_FALSE;

		ddsd.dwSize = sizeof( ddsd );
		while( ( hres = pdds->Lock( NULL, &ddsd, 0, NULL ) ) == DDERR_WASSTILLDRAWING );
		if ( hres == DD_OK )  
		{
			dw = *(DWORD *) ddsd.lpSurface;
			if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 )
				dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
			pdds->Unlock( NULL );

		}

		if( rgb != CLR_INVALID && pdds->GetDC( &hdc ) == DD_OK )
		{
			SetPixel( hdc, 0, 0, rgbT );
			pdds->ReleaseDC( hdc );

		}
		else
			return S_FALSE;

		ddck.dwColorSpaceLowValue = dw;
		ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
		return pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );

	}

	return S_OK;

}



bool CDDraw::ShowScene( ImagingHelper *imBlack, int iSpeed, bool bShow )
{
	bool bFinish = false;

	BLENDFUNCTION bf_Black;
	bf_Black.BlendOp = AC_SRC_OVER;   
	bf_Black.BlendFlags = 0;   
	bf_Black.AlphaFormat = 0;   

	if( bShow == true )
	{
		static int iAlpha = 255;
		iAlpha -= iSpeed;
		if( iAlpha <= 0 )
		{
			iAlpha = 255;
			bFinish = true;
			bf_Black.SourceConstantAlpha = 0; 

		}
		else
		{
			bFinish = false;
			bf_Black.SourceConstantAlpha = iAlpha; 

		}

	}
	else
	{
		static int iAlpha = 0;
		iAlpha += iSpeed;
		if( iAlpha >= 255 )
		{
			iAlpha = 0;
			bFinish = true;
			bf_Black.SourceConstantAlpha = 255; 

		}
		else
		{
			bFinish = false;
			bf_Black.SourceConstantAlpha = iAlpha; 

		}

	}

	LoadBackSurfaceDC();
	AlphaBlend( m_hDC, 0, 0, m_BackRect.right - m_BackRect.left, m_BackRect.bottom - m_BackRect.top, imBlack->GetDC(), 0, 0, imBlack->GetImageWidth(), imBlack->GetImageWidth(), bf_Black );

	return bFinish;

}



//
static HRESULT PASCAL
EnumFunction(LPDIRECTDRAWSURFACE pSurface,
			 LPDDSURFACEDESC lpSurfaceDesc,
			 LPVOID  lpContext)
{
	static BOOL bCalled = FALSE;

	if (!bCalled)
	{
		*((LPDIRECTDRAWSURFACE *)lpContext) = pSurface;
		bCalled = TRUE;
		return DDENUMRET_OK;
	}
	else
	{
		OutputDebugString(L"DDEX2: Enumerated more than surface?");
		pSurface->Release();
		return DDENUMRET_CANCEL;
	}

}




CDDraw g_CDDraw;